package com.dns.server.secondary;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class DomainDataHandler {
	public
	static Map<String,String> DomainToIPMap;
	static Map<String,String> IPToDomainMap;
	static Map<String,Object> DomainToTTLMap;
	static ReentrantReadWriteLock readWriteLock;
	static Lock read;
	static Lock write;
	
	public

	static void initialize()
	{
		readWriteLock = new ReentrantReadWriteLock();
		read  = readWriteLock.readLock();
		write = readWriteLock.writeLock();		
	}
	
	static void readDomainDataFile() throws IOException
	{
		DomainToIPMap = new HashMap<String, String>();
		IPToDomainMap = new HashMap<String, String>();
		DomainToTTLMap = new HashMap<String, Object>();
		
		FileInputStream fstream = new FileInputStream(Configurations.domainDataFile);
		
		DataInputStream inputStream = new DataInputStream(fstream);
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
		String strLine;
		
		//Read File Line By Line
		while ((strLine = bufferedReader.readLine()) != null)   {
			parseFileDataLineAndAddToMap(strLine);
		}
		  //Close the input stream
		inputStream.close();
		
		System.out.println("Successfully Read Domain Data\n");
	}
	
	static void writeDomainDataFile() throws IOException
	{	
		
		File domainDataFile = new File(Configurations.domainDataFile);
		FileOutputStream outputFileStream = null;
		outputFileStream = new FileOutputStream(domainDataFile, false);
		
		@SuppressWarnings("rawtypes")
		Set domainMapSet = DomainToIPMap.entrySet();
		
        //Move next key and value of Map by iterator
        @SuppressWarnings("rawtypes")
		Iterator domainMapSetIterator = domainMapSet.iterator();

        while(domainMapSetIterator.hasNext())
        {
        	String fileLine = new String();
            
            @SuppressWarnings("rawtypes")
			Map.Entry mapEntry =(Map.Entry)domainMapSetIterator.next();

            String domainName = (String)mapEntry.getKey();
            
            String ip = (String)mapEntry.getValue();

            int ttl = (Integer)DomainToTTLMap.get(domainName);            
            
            fileLine  = domainName + " " + ip + " " + ttl;
            
            byte byteArray[] = fileLine.getBytes();
            outputFileStream.write(byteArray);
            outputFileStream.write('\n');            
        }	
		
        outputFileStream.flush();
        outputFileStream.close();
	}

	static String getIPFromDomain(String domainName)
	{
		read.lock();
		String ip = null;
		
		ip = (String)DomainToIPMap.get(domainName);
		
		if(ip == null)
			;//System.out.println("DomainDataHandler: FAILED: Domain to IP Search");
		else
			;//System.out.println("DomainDataHandler: SUCCESS: Domain to IP Search");
		
		read.unlock();
		return ip;
		
	}
	
	static String getDomainFromIP(String ip)
	{
		read.lock();
		String domain = null;
		
		domain = (String)IPToDomainMap.get(ip);

		if(domain == null)
			;//System.out.println("DomainDataHandler: FAILED:  IP to Domain Search");
		else
			;//System.out.println("DomainDataHandler: SUCCESS: IP to Domain Search");
		
		read.unlock();
		return domain;
	}
	
	static int getTTLFromDomain(String domainName)
	{
		read.lock();
		int ttl;
		
		ttl = (Integer)DomainToTTLMap.get(domainName);
		
		read.unlock();
		return ttl;
		
	}
	
	static int updateDomain(String domainName, String newIP, int ttl) throws IOException
	{
		write.lock();
		int status = 1;
		String ip = null;
		
		ip = (String)DomainToIPMap.get(domainName);
		
		if(ip != null)
		{
			status = 0;
			//Check whether IP is alread taken.
			DomainToIPMap.remove(domainName);
			DomainToIPMap.put(domainName, newIP);
      DomainToTTLMap.remove(domainName);
			DomainToTTLMap.put(domainName, ttl);      
			IPToDomainMap.remove(ip);
			IPToDomainMap.put(newIP, domainName);
			writeDomainDataFile();
			readDomainDataFile();
			//System.out.println("DomainDataHandler: Update SUCCESS");
		}
		else
		{
			status = 0;
			DomainToIPMap.put(domainName, newIP);
			IPToDomainMap.put(newIP, domainName);
			DomainToTTLMap.put(domainName, ttl);
			writeDomainDataFile();
			readDomainDataFile();
		}
		
		write.unlock();
		return status;
	}	
	
	private
	
	static void parseFileDataLineAndAddToMap(String line)
	{
		 StringTokenizer tokenizer = new StringTokenizer(line);
		 
		 String domainName = tokenizer.nextToken();
		 String ip = tokenizer.nextToken();
		 int ttl = Integer.parseInt(tokenizer.nextToken());

		DomainToIPMap.put(domainName, ip);
		IPToDomainMap.put(ip, domainName);
		DomainToTTLMap.put(domainName, new Integer(ttl));		
	}
}
